/**
 * CaddieProductPane.java 21 juil. 07
 *
 * Copyright (c) 2007 windu.2b <jcaddie@windu2b.org>. All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.windu2b.jcaddie.swing;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import javax.swing.*;

import org.windu2b.jcaddie.model.*;

/**
 * Caddie product editing panel.
 * @author windu.2b
 * 
 */
public class CaddieProductPane extends JPanel
{
	/**
	 * 
	 */
	private static final long	    serialVersionUID	= 6749876225173106369L;


	private CaddieProductController	controller;


	private ResourceBundle	        resource;


	private JLabel	                nameLabel;


	private JTextField	            nameTextField;


	private JLabel	                colorLabel;


	private ColorButton	            colorButton;


	private NullableCheckBox	    visibleCheckBox;




	/**
	 * Creates a panel that displays caddie product data according to the units
	 * set in <code>preferences</code>.
	 * 
	 * @param caddie
	 *            caddie from which selected product is edited by this panel
	 * @param preferences
	 *            user preferences
	 * @param controller
	 *            the controller of this panel
	 */
	public CaddieProductPane( Caddie caddie, UserPreferences preferences,
	        CaddieProductController controller )
	{
		super( new GridBagLayout() );
		this.controller = controller;
		this.resource = ResourceBundle.getBundle( CaddieProductPane.class
		        .getName() );
		createComponents( preferences );
		setMnemonics();
		layoutComponents();
		updateComponents( caddie );
	}




	/**
	 * @param caddie
	 */
	private void updateComponents( Caddie caddie )
	{
		// TODO à compléter
	}




	/**
	 * Returns the edited name of the product or <code>null</code>.
	 */
	public String getProductName()
	{
		String name = this.nameTextField.getText();
		if ( name == null || name.trim().length() == 0 )
		{
			return null;
		}
		else
		{
			return name;
		}
	}




	/**
	 * 
	 */
	private void layoutComponents()
	{

	}




	/**
	 * Sets components mnemonics and label / component associations.
	 */
	private void setMnemonics()
	{
		if ( !System.getProperty( "os.name" ).startsWith( "Mac OS X" ) )
		{
			this.nameLabel.setDisplayedMnemonic( KeyStroke.getKeyStroke(
			        this.resource.getString( "nameLabel.mnemonic" ) )
			        .getKeyCode() );
			this.nameLabel.setLabelFor( this.nameTextField );
			this.colorLabel.setDisplayedMnemonic( KeyStroke.getKeyStroke(
			        this.resource.getString( "colorLabel.mnemonic" ) )
			        .getKeyCode() );
			this.colorLabel.setLabelFor( this.colorButton );
			this.visibleCheckBox.setMnemonic( KeyStroke.getKeyStroke(
			        this.resource.getString( "visibleCheckBox.mnemonic" ) )
			        .getKeyCode() );
		}
	}




	/**
	 * @param preferences
	 */
	private void createComponents( UserPreferences preferences )
	{
		// Get unit text matching current unit
		String unitText = this.resource
		        .getString( preferences.getUnit() == UserPreferences.Unit.LITRE ? "litreUnit"
		                : "gallonUnit" );
		this.nameLabel = new JLabel( this.resource.getString( "nameLabel.text" ) );
		this.nameTextField = new JTextField( 10 );
		this.colorLabel = new JLabel( this.resource
		        .getString( "colorLabel.text" ) );
		this.colorButton = new ColorButton();
		this.colorButton.setColorDialogTitle( this.resource
		        .getString( "colorDialog.title" ) );
		this.visibleCheckBox = new NullableCheckBox( this.resource
		        .getString( "visibleCheckBox.text" ) );

	}




	/**
	 * Displays this panel in a modal dialog box.
	 */
	public void displayView()
	{
		String dialogTitle = resource.getString( "caddieProduct.title" );
		Component parent = null;
		for ( Frame frame : Frame.getFrames() )
		{
			if ( frame.isActive() )
			{
				parent = frame;
				break;
			}
		}
		if ( JOptionPane.showConfirmDialog( parent, this, dialogTitle,
		        JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE ) == JOptionPane.OK_OPTION
		        && this.controller != null )
		{
			this.controller.modifySelection();
		}
	}



	/**
	 * A check box that accepts <code>null</code> values. Thus this check box
	 * is able to display 3 states : <code>null</code>, <code>false</code>
	 * and <code>true</code>.
	 */
	private static class NullableCheckBox extends JComponent
	{
		/**
		 * 
		 */
		private static final long	serialVersionUID	= 735674619455004255L;


		private JCheckBox		  checkBox;


		private Boolean		      value		         = Boolean.TRUE;


		private boolean		      nullable;


		private ItemListener		checkBoxListener;




		/**
		 * Creates a nullable check box.
		 */
		public NullableCheckBox( String text )
		{
			// Measure check box size alone without its text
			final Dimension checkBoxSize = new JCheckBox().getPreferredSize();
			// Create a check box that displays a dash upon default check box
			// for a null value
			this.checkBox = new JCheckBox( text )
			{
				/**
				 * 
				 */
				private static final long	serialVersionUID	= 5395613077419942092L;




				@Override
				protected void paintComponent( Graphics g )
				{
					super.paintComponent( g );
					if ( value == null )
					{
						g.drawRect( checkBoxSize.width / 2 - 3,
						        checkBoxSize.height / 2, 6, 1 );
					}
				}
			};
			// Add an item listener to change default checking logic
			this.checkBoxListener = new ItemListener()
			{
				public void itemStateChanged( ItemEvent ev )
				{
					// If this check box is nullable
					if ( nullable )
					{
						// Checking sequence will be null, true, false
						if ( getValue() == Boolean.FALSE )
						{
							setValue( null );
						}
						else if ( getValue() == null )
						{
							setValue( Boolean.TRUE );
						}
						else
						{
							setValue( Boolean.FALSE );
						}
					}
					else
					{
						setValue( checkBox.isSelected() );
					}
				}
			};
			this.checkBox.addItemListener( this.checkBoxListener );

			// Add the check box and its label to this component
			setLayout( new BorderLayout( 2, 0 ) );
			add( this.checkBox, BorderLayout.WEST );
		}




		/**
		 * Returns <code>null</code>, <code>Boolean.TRUE</code> or
		 * <code>Boolean.FALSE</code>.
		 */
		public Boolean getValue()
		{
			return this.value;
		}




		/**
		 * Sets displayed value in check box.
		 * 
		 * @param value
		 *            <code>null</code>, <code>Boolean.TRUE</code> or
		 *            <code>Boolean.FALSE</code>
		 */
		public void setValue( Boolean value )
		{
			this.value = value;
			this.checkBox.removeItemListener( this.checkBoxListener );
			try
			{
				if ( value != null )
				{
					this.checkBox.setSelected( value );
				}
				else if ( isNullable() )
				{
					// Unselect check box to display a dash in its middle
					this.checkBox.setSelected( false );
				}
				else
				{
					throw new IllegalArgumentException(
					        "Check box isn't nullable" );
				}
			}
			finally
			{
				this.checkBox.addItemListener( this.checkBoxListener );
			}
		}




		/**
		 * Returns <code>true</code> if this check box is nullable.
		 */
		public boolean isNullable()
		{
			return this.nullable;
		}




		/**
		 * Sets whether this check box is nullable.
		 */
		public void setNullable( boolean nullable )
		{
			this.nullable = nullable;
			if ( !nullable && getValue() == null )
			{
				setValue( Boolean.FALSE );
			}
		}




		/**
		 * Sets the mnemonic of this component.
		 * 
		 * @param mnemonic
		 *            a <code>VK_...</code> code defined in
		 *            <code>java.awt.event.KeyEvent</code>.
		 */
		public void setMnemonic( int mnemonic )
		{
			this.checkBox.setMnemonic( mnemonic );
		}




		/**
		 * Returns the mnemonic of this component.
		 */
		public int getMnemonic()
		{
			return this.checkBox.getMnemonic();
		}




		@Override
		public void setEnabled( boolean enabled )
		{
			this.checkBox.setEnabled( enabled );
		}




		@Override
		public boolean isEnabled()
		{
			return this.checkBox.isEnabled();
		}
	}
}